package com.pic.mgt.executer;

import java.util.List;

import org.springframework.dao.DataAccessException;

import com.pic.mgt.IgxStatus;
import com.pic.mgt.dao.IBusinessMgtDao;
import com.pic.mgt.log.IgxLog;
import com.pic.mgt.manager.business.ApInfoBean;
import com.pic.mgt.unit.Business;
import com.pic.mgt.utils.LogUtils;

public abstract class BusinessUnitExecuter extends UnitExecuter {
	protected IBusinessMgtDao businessMgtDao;
	
	protected TargetAction targetAction;
	
	protected Business business;
	
	protected BusinessUnitExecuter(TargetAction targetAction) {
		this.targetAction = targetAction;
	}
	
	@Override
	protected void updateStatusWhenBeginExecution() throws DataAccessException {
		// throws DataAccessException
		businessMgtDao.updateStatusByUnitName(
				IgxStatus.BUSINESS_EXECUTING, super.unit.getUnitName());
		
		// ********************** Log **********************
		if (IgxLog.messageLog.isTraceMode()) {
			IgxLog.messageLog.trace(this,
					"Update status to db table '{}' for unit '{}' completed.",
					this.businessMgtDao.getTableName(),
					super.unit.getUnitName());
		}
		// ********************** Log **********************
	}
	
	@Override
	protected void updateStatusWhenExecutionSuccess()
			throws DataAccessException {
		// throws DataAccessException
		updateStatusByUnitName(IgxStatus.BUSINESS_COMPLETED);
		
		// ********************** Log **********************
		if (IgxLog.messageLog.isTraceMode()) {
			IgxLog.messageLog.trace(this,
					"Update status to db table '{}' for unit '{}' completed.",
					this.businessMgtDao.getTableName(),
					super.unit.getUnitName());
		}
		// ********************** Log **********************
	}
	
	@Override
	protected void updateStatusWhenExecutionfailed() throws DataAccessException {
		// throws DataAccessException
		updateStatusByUnitName(IgxStatus.BUSINESS_FAILED);
		
		// ********************** Log **********************
		if (IgxLog.messageLog.isTraceMode()) {
			IgxLog.messageLog.trace(this,
					"Update status to db table '{}' for unit '{}' completed.",
					this.businessMgtDao.getTableName(),
					super.unit.getUnitName());
		}
		// ********************** Log **********************
	}
	
	@Override
	public void executeUnitType() throws UnitTypeExecutionException {
		this.business = (Business)super.unit;
		
		// 執行目標檔案的處理 (配信/集信皆有的目標檔案執行動作)
		try {
			// (送多方修改)
			List<ApInfoBean> apInfoBeanList = getSyncApList();
			if (null == apInfoBeanList) { // 不需使用同步化來執行
				// throws TargetFileProcessException
				performTargetAction();
				
				// 若目標檔案處理完成,則再針對個別配信或集信所需的其它執行動作
				executeIGXTypeSpecify();
			}
			else { // 需要使用同步化來執行
				synchronized(apInfoBeanList) {
					// throws TargetFileProcessException
					performTargetAction();
					
					// 若目標檔案處理完成,則再針對個別配信或集信所需的其它執行動作
					executeIGXTypeSpecify();
				}
			}
		} catch (TargetFileProcessException e) {
			// ********************** Log **********************
			LogUtils.error(this, IgxLog.messageDetailsLog, e);
			// ********************** Log **********************
			
			throw new UnitTypeExecutionException(
					"SUDA-209 Business '" + business.getUnitName() +
					"' execution failed in target file process.", e);
		} catch (IGXTypeExecutionException e) {
			// ********************** Log **********************
			LogUtils.error(this, IgxLog.messageDetailsLog, e);
			// ********************** Log **********************
			
			throw new UnitTypeExecutionException(
					"SUDA-210 Business '" + business.getUnitName() +
					"' execution failed in IGX type process.", e);
		}
	}
	
	/**
	 *  執行目標檔案的處理。
	 */
	private void performTargetAction()
							throws TargetFileProcessException {
		// ********************** Log **********************
		if (IgxLog.messageLog.isDebugMode()) {
			IgxLog.messageLog.debug(this,
					"Performing target action for business '{}'.", super.unit
							.getUnitName());
		}
		// ********************** Log **********************
		
		// 執行指示配信目標檔案的處理 動作。
		// throws DeTarProcessException
		this.targetAction.perform(this.business);
		
		// ********************** Log **********************
		if (IgxLog.messageLog.isDebugMode()) {
			IgxLog.messageLog.debug(this,
					"Performing target action for business '{}' completed.",
					super.unit.getUnitName());
		}
		// ********************** Log **********************
	}
	
	
	/**
	 *  針對個別配信或集信所需的其它執行動作。
	 */
	protected abstract void executeIGXTypeSpecify()
							throws IGXTypeExecutionException;
	
	protected void updateStatusByUnitName(String statusValue) throws DataAccessException {
		try {
			// throws DataAccessException
			this.businessMgtDao.updateStatusByUnitName(
								statusValue, super.unit.getUnitName());
		} catch (DataAccessException e) {
			// ********************** Log **********************
			IgxLog.messageDetailsLog.error(this, e.getMessage());
			// ********************** Log **********************
			
			// ********************** Log **********************
			IgxLog.messageLog
					.error(
							this,
							"Update status to db table '{}' for unit '{}' failed.",
							this.businessMgtDao.getTableName(),
							super.unit.getUnitName());
			// ********************** Log **********************
			
			throw e;
		}
	}
	
	/**
	 * 給 BusinessUnitExecuter 判斷，在執行業務的處理時，是否要對業務的 AP List 進行同步。
	 * @return 若 為null作不會同步；若不為 null 則會對該回傳的 List進行同步
	 */
	// (送多方新增)
	protected List<ApInfoBean> getSyncApList() {
		return null;
	}
	
	// --- getter and setter ---

	public void setBusinessMgtDao(IBusinessMgtDao businessMgtDao) {
		this.businessMgtDao = businessMgtDao;
	}	
}
